package com.gitee.shoes.exception;

import cn.hutool.core.util.StrUtil;
import com.gitee.shoes.utils.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.nio.file.AccessDeniedException;
import java.util.List;


/**
 * @author LYH
 */
@Slf4j
public abstract class GlobalExceptionHandler {

    /**
     * 业务异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(BadRequestException.class)
    public Result handlerBizException(BadRequestException ex) {
        return Result.fail(ex.getMessage());
    }

    /**
     * 不支持的请求方式
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException ex) {
        log.warn("HttpRequestMethodNotSupportedException:", ex);
        return Result.fail(ex.getMessage());
    }


    /**
     * 参数类型不匹配
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public Result handlerMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException ex) {
        log.warn("MethodArgumentTypeMismatchException:", ex);
        StringBuilder msg = new StringBuilder("参数[").append(ex.getName())
                .append("]的传入值[").append(ex.getValue())
                .append("]与预期的字段类型[").append(ex.getRequiredType().getName()).append("]不匹配");
        return Result.fail(msg.toString());
    }

    /**
     * 参数错误
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Result httpMessageNotReadableException(HttpMessageNotReadableException ex) {
        log.warn("HttpMessageNotReadableException:", ex);
        String message = ex.getMessage();
        if (StrUtil.containsAny(message, "Could not read document:")) {
            message = String.format("无法正确的解析json类型的参数：%s", StrUtil.subBetween(message, "Could not read document:", " at "));
        }
        if (StrUtil.containsAny(message, "not one of the values accepted for Enum class:")) {
            message = "枚举异常值";
        }
        return Result.fail(message);
    }

    /**
     * spring 封装的参数验证异常， 在conttoller中没有写result参数时，会进入
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result handlerMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.warn("MethodArgumentNotValidException:", ex);
        FieldError fieldError = ex.getBindingResult().getFieldError();
        String message = StrUtil.format("参数[{}]{}", fieldError.getField(), fieldError.getDefaultMessage());
        return Result.fail(message);
    }

    /**
     * 参数缺失
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Result handlerMissingServletRequestParameterException(MissingServletRequestParameterException ex) {
        log.warn("MissingServletRequestParameterException:", ex);
        String msg = StrUtil.format("缺少必须的[{}]类型的参数", ex.getParameterType());
        return Result.fail(msg);
    }

    /**
     * 参数异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(BindException.class)
    public Result bindException(BindException ex) {
        log.warn("BindException:", ex);
        try {
            String msg = ex.getBindingResult().getFieldError().getDefaultMessage();
            if (StrUtil.isNotEmpty(msg)) {
                return Result.fail(msg);
            }
        } catch (Exception ee) {
        }
        StringBuilder msg = new StringBuilder();
        List<FieldError> fieldErrors = ex.getFieldErrors();
        fieldErrors.forEach((oe) ->
                msg.append("参数:[").append(oe.getObjectName())
                        .append(".").append(oe.getField())
                        .append("]的传入值:[").append(oe.getRejectedValue()).append("]与预期的字段类型不匹配.")
        );
        return Result.fail(msg.toString());
    }

    /**
     * 缺失权限
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(AccessDeniedException.class)
    public Result handlerException(AccessDeniedException ex) {
        log.warn("AccessDeniedException:", ex);
        String message = ex.getMessage();
        if (StrUtil.isEmpty(message)) {
            return Result.fail("权限拒绝");
        }
        return Result.fail(message);
    }

    /**
     * 其他异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(Exception.class)
    public Result handlerException(Exception ex) {
        log.error("Exception:", ex);
        String message = ex.getMessage();
        if (StrUtil.isEmpty(message)) {
            return Result.fail("系统异常");
        }
        return Result.fail(message);
    }


}
